/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.service.core.impl;

import com.blandware.atleap.model.core.GlobalProperty;
import com.blandware.atleap.persistence.core.GlobalPropertyDAO;
import com.blandware.atleap.service.core.GlobalPropertyManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * <p>Implementation of GlobalPropertyManager interface.
 * </p>
 * <p><a href="GlobalPropertyManagerImpl.java.html"> <i>View Source </i> </a>
 * </p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com">&lt;andrey.grebnev@blandware.com&gt;</a>
 * @version $Revision: 1.11 $ $Date: 2006/08/03 10:07:42 $
 */
public class GlobalPropertyManagerImpl extends BaseManagerImpl implements GlobalPropertyManager {

	protected final Log log = LogFactory.getLog(GlobalPropertyManagerImpl.class);

    /**
     * Global property DAO
     */
	protected GlobalPropertyDAO globalPropertyDAO;

	/**
	 * Static properties
	 */
	protected Properties staticProperties;

	/**
	 * Dynamic properties
	 */
	protected Properties dynamicProperties;

	/**
	 * Original dynamic properties if user wants to perform reload
	 */
	protected Properties originalDynamicProperties;

    /**
     * Sets DAO for operating with global properties
     *
     * @param dao the DAO to set
     */
	public void setGlobalPropertyDAO(GlobalPropertyDAO dao) {
		this.globalPropertyDAO = dao;
	}

    /**
     * Sets static properties (those that can't be changed in application)
     *
     * @param staticProperties static properties to set
     */
	public void setStaticProperties(Properties staticProperties) {
		this.staticProperties = staticProperties;
	}

    /**
     * Sets dynamic properties (those that can be changed in application)
     *
     * @param dynamicProperties dynamic properties to set
     */
	public void setDynamicProperties(Properties dynamicProperties) {
		this.dynamicProperties = dynamicProperties;
	}

    /**
     * Gets static properties (those that can't be changed in application)
     *
     * @return static properties
     */
	public Properties getStaticProperties() {
		return staticProperties;
	}

    /**
     * Gets dynamic properties (those that can be changed in application)
     *
     * @return dynamic properties
     */
	public Properties getDynamicProperties() {
		return dynamicProperties;
	}

	/**
	 * @see com.blandware.atleap.service.core.GlobalPropertyManager#loadDynamicProperties(boolean)
	 */
	public Properties loadDynamicProperties(boolean overrideDynamicValues) {
        // Find the properties that are both static and dynamic (to warn user)
		Set intersection = new HashSet(staticProperties.keySet());
		intersection.retainAll(dynamicProperties.keySet());
		if ( !intersection.isEmpty() ) {
			// warn user
			if ( log.isWarnEnabled() ) {
				for ( Iterator i = intersection.iterator(); i.hasNext(); ) {
					String name = (String) i.next();
					log.warn("Property with name '" + name + "' declared as static and dynamic simultaneously. Static value will never be returned.");
				}
			}
		}

		// delete properties which names are not presented in the list
		List existentProperties = listDynamicProperties();
		for ( Iterator i = existentProperties.iterator(); i.hasNext(); ) {
			GlobalProperty globalProperty = (GlobalProperty) i.next();
			if ( !this.dynamicProperties.keySet().contains(globalProperty.getName()) ) {
				globalPropertyDAO.deleteGlobalProperty(globalProperty);
			}
		}


		Properties properties = new Properties();

		// create unexistent properties and update dynamic properties map
		for ( Iterator i = this.dynamicProperties.entrySet().iterator(); i.hasNext(); ) {
			Map.Entry property = (Map.Entry) i.next();
			String name = (String) property.getKey();
			String value = (String) property.getValue();
            if (log.isDebugEnabled()) {
                log.debug("Creating unexistent property with name='" + name + "' and value='" + value + "'");
            }
			GlobalProperty globalProperty = globalPropertyDAO.retrieveGlobalProperty(name);
			if ( globalProperty == null ) {
				globalProperty = new GlobalProperty(name, value);
				globalPropertyDAO.createGlobalProperty(globalProperty);
			} else if ( overrideDynamicValues && !value.equals(globalProperty.getValue()) ) {
				globalProperty.setValue(value);
				globalPropertyDAO.updateGlobalProperty(globalProperty);
			} else {
				value = globalProperty.getValue();
                if (value == null) {
                    value = "";
                }
			}
			properties.put(name, value);
		}
		return properties;
	}

	/**
	 * @see com.blandware.atleap.service.core.GlobalPropertyManager#retrieveGlobalProperty(String)
	 */
	public GlobalProperty retrieveGlobalProperty(String propertyName) {
		return globalPropertyDAO.retrieveGlobalProperty(propertyName);
	}


	/**
	 * @see com.blandware.atleap.service.core.GlobalPropertyManager#updateProperty(com.blandware.atleap.model.core.GlobalProperty)
	 */
	public void updateProperty(GlobalProperty globalProperty) {
        // remove global property from cache in order to prevent Hibernate from assigning new version number
		globalPropertyDAO.removeFromCache(globalProperty);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating global property with name '" + globalProperty.getName() + "'...");
		}

		globalPropertyDAO.updateGlobalProperty(globalProperty);

		if ( log.isDebugEnabled() ) {
			log.debug("Global property has been updated successfully");
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.core.GlobalPropertyManager#listDynamicProperties()
	 */
	public List listDynamicProperties() {
		return globalPropertyDAO.listDynamicProperties();
	}

}